#include "app/aerApplication.hpp"
#include "app/aerWindow.hpp"
#include "app/aerEventHandler.hpp"
#include "device/aerProgram.hpp"
#include "device/aerDeviceBuffer.hpp"
#include "aerMesh.hpp"


namespace aer {
  
class SimpleWindowApp : public aer::Application
{
  private:
    Program m_program;
    
    DeviceBuffer m_vbuffer;
    Mesh m_mesh;
    
    bool m_bUseMesh;
    
    
  public:
    SimpleWindowApp() : Application()
    {
      /// Window
      createWindow( Window::sDisplay_GL33_800x600, "A simple window" );
            
      /// GLSL Program
      const char *vSource =
        "#version 330\n"
        "layout(location=0) in vec2 inPosition;"
        "void main() { gl_Position = vec4( inPosition, 0.0f, 1.0f); }";
      
      const char *fSource =
        "#version 330\n"
        "uniform vec3 uColor = vec3( 0.0f, 0.5f, 0.5f);"
        "void main() { gl_FragColor = vec4( uColor, 1.0f );}";
      
      m_program.generate();
        m_program.addShaderSrc( Program::VERTEX_SHADER,   vSource );
        m_program.addShaderSrc( Program::FRAGMENT_SHADER, fSource );
      m_program.link();
      

      /// Mesh (2 ways)
      const float vertices[] = { -0.5f, -0.5f,   0.5f, -0.5f,   0.5f, 0.5f };
      
      // 1) Set a DeviceBuffer manually
      m_vbuffer.generate();
      m_vbuffer.bind( DeviceBuffer::ARRAY );
        m_vbuffer.setData( vertices, sizeof(vertices) );
        glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0 );
      m_vbuffer.unbind();
      
      // OR
      // 2) Use a Mesh
      m_mesh.setAttrib( Mesh::POSITION, vertices, 2, 3);//
      m_mesh.setPrimitiveType( GL_TRIANGLES );
      m_mesh.upload( DeviceBuffer::STATIC_DRAW );
      
      m_bUseMesh = false;
    }
    
    ~SimpleWindowApp()
    {
      m_program.release();
      m_vbuffer.release();
    }
    
    
    void updateFrame()
    {
      if (EventHandler::IsKeyPressed( sf::Keyboard::Escape )) quit();
      if (EventHandler::IsKeyPressed( sf::Keyboard::M )) m_bUseMesh = !m_bUseMesh;
    }
    
    void drawFrame()
    {
      glClear( GL_COLOR_BUFFER_BIT );
      
      m_program.bind();
        Vector3 color( 0.35f, 0.0f, 0.15f);
        
        if (m_bUseMesh)
        {
          m_program.setUniform( "uColor", color );
          m_mesh.draw();
        }
        else
        {
          m_program.setUniform( "uColor", 1.0f - color );
          glEnableVertexAttribArray( 0 );
          m_vbuffer.bind();          
            glDrawArrays( GL_TRIANGLES, 0, m_vbuffer.getSize() );
          m_vbuffer.unbind();
          glDisableVertexAttribArray( 0 );
        }
        
      m_program.unbind();
    }
    
    void init()
    {
      const Display &display = m_Window->getDisplay();
      glViewport( 0.0f, 0.0f, display.width, display.height );
    }
};
  
} // aer



int main(int argc, char *argv[])
{
  aer::SimpleWindowApp app;
  
  app.run();
    
  return EXIT_SUCCESS;
}

